//
// Created by Win on 2015/11/24.

#include <stdio.h>

#include "frcomm.h"
#include "frmem.h"
#include "iconv2utf8.h"
#include "dcom_comm.h"

/*!
 * dcom ctx short 获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_s_out					(short *				输出)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_ctx_short(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, short *p_s_out, int i_flag_need)
{
	int i_ret = 0;
	short s_value = 0;

	if(p_st_data == NULL)
		return FR_FAIL;

	if(i_flag_need && (p_st_private == NULL || p_s_out == NULL))
		return FR_FAIL;

	if(i_flag_need)
		i_ret = bytebuff_get_short(p_st_data, 2, (uint16_t *)&s_value, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	else
		i_ret = bytebuff_skip (p_st_data, 2);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

    if(i_flag_need)
	    *p_s_out = s_value;
	return FR_SUCC;

}

/*!
 * dcom guid 获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \pp_out					(char *					输出)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_ctx_guid(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, char **pp_out, int i_flag_need)
{
	int i_ret = 0;
	char *p_out = NULL, *p_pos = NULL;
	int i_loop = 0, i_index = 0;

	unsigned char arr_first_4byte[4], arr_mid_2byte[2], arr_last_6byte[6];

	if(p_st_data == NULL)
		return FR_FAIL;

	if(i_flag_need && (p_st_private == NULL || pp_out == NULL))
		return FR_FAIL;

	if(i_flag_need == FR_NO)
	{
		i_ret = bytebuff_skip(p_st_data, 16);

		return i_ret;
	}

	p_out = (char*)frmalloc(37);
	if(p_out == NULL)
		return FR_FAIL;

	p_pos = p_out;

	i_ret = bytebuff_get_bytes(p_st_data, arr_first_4byte, 4);
	if(i_ret == FR_FAIL)
		goto ERROR;

	//
	for(i_loop = 3; i_loop >= 0; i_loop--)
	{
		snprintf(p_pos, 3, "%02x", (int)arr_first_4byte[i_loop]);
		p_pos += 2;
	}

	for (i_index = 2; i_index > 0; i_index--)
	{
		*p_pos = '-';
		p_pos ++;

		i_ret = bytebuff_get_bytes(p_st_data, arr_mid_2byte, 2);
		if(i_ret == FR_FAIL)
			goto ERROR;

		for(i_loop = 1; i_loop >= 0; i_loop--)
		{
			snprintf(p_pos, 3, "%02x", (int)arr_mid_2byte[i_loop]);
			p_pos += 2;
		}
	}

    *p_pos = '-';
    p_pos ++;

    i_ret = bytebuff_get_bytes(p_st_data, arr_mid_2byte, 2);
    if(i_ret == FR_FAIL)
        goto ERROR;

    for(i_loop = 0; i_loop < 2; i_loop++)
    {
        snprintf(p_pos, 3, "%02x", (int)arr_mid_2byte[i_loop]);
        p_pos += 2;
    }

	i_ret = bytebuff_get_bytes(p_st_data, arr_last_6byte, 6);
	if(i_ret == FR_FAIL)
		goto ERROR;

	*p_pos = '-';
	p_pos ++;

	//
	for(i_loop = 0; i_loop < 6; i_loop++)
	{
		snprintf(p_pos, 3, "%02x", (int)arr_last_6byte[i_loop]);
		p_pos += 2;
	}

	*pp_out = p_out;
	return FR_SUCC;

ERROR:
	if(p_out)
		frfree(p_out);

	return FR_FAIL;

}

/*!
 * dcom ctx item获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_ctx_item(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	int i_items_num = 0;
	char *p_transfer_syntax = NULL;

	if(p_st_data == NULL || p_st_private == NULL)
		return FR_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
	return FR_FAIL;

	//context id
	i_ret = dcom_ctx_short(p_st_data, p_st_private, NULL, FR_NO);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//items num
	i_ret = bytebuff_get_int(p_st_data, 1, (uint32_t *)&i_items_num, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//dcerpc.cn_bind_trans
	while (i_items_num)
	{
		//dcerpc.cn_bind_abstract_syntax
		i_ret = bytebuff_skip(p_st_data, 20);
		if(i_ret == FR_FAIL)
			return FR_FAIL;

		// UUID
		//transfer syntax
		i_ret = dcom_ctx_guid(p_st_data, p_st_private, &p_transfer_syntax, i_flag_need);
		if(i_ret == FR_FAIL)
			return FR_FAIL;

    if(i_flag_need)
    {
        if(p_st_private->i_use_request)
            i_ret = frreport_body_l7_add_str(p_st_body_data, "request.transfer.syntax", p_transfer_syntax);
        else
            i_ret = frreport_body_l7_add_str(p_st_body_data, "response.transfer.syntax", p_transfer_syntax);
        frfree(p_transfer_syntax);
        if(i_ret == FR_FAIL)
            return FR_FAIL;
    }

		i_items_num--;
	}



	return FR_SUCC;

}

/*!
 * dcom ctx item ack获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_ctx_item_ack(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	char *p_transfer_syntax = NULL;

	if(p_st_data == NULL || p_st_private == NULL)
		return FR_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
	return FR_FAIL;

	//ack result
	i_ret = bytebuff_skip (p_st_data, 4);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//dcerpc.cn_ack_trans_id
	i_ret = dcom_ctx_guid(p_st_data, p_st_private, &p_transfer_syntax, i_flag_need);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

    if(i_flag_need)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, "response.transfer.syntax", p_transfer_syntax);
        frfree(p_transfer_syntax);
        if(i_ret == FR_FAIL)
            return FR_FAIL;

    }


	//version
	i_ret = bytebuff_skip (p_st_data, 4);

	return i_ret;

}

/*!
 * dcom 字符串获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \i_start					(int					起始位置)
 * \pp_out					(char **				字符串内容出力 外部释放内存)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_get_string(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, int i_start, char **pp_out, int i_flag_need)
{
	char *p_out = NULL, *p_tmp = NULL;
	int i_ret = 0, i_out_size = 0;
	int i_len = 0, i_off_set = 0;

	if(p_st_data == NULL || p_st_private == NULL)
		return FR_FAIL;

	if(i_flag_need && pp_out == NULL)
		return FR_FAIL;
	//len
	i_ret = bytebuff_get_int (p_st_data, 2, (uint32_t *)&i_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//max len
	i_ret = bytebuff_skip (p_st_data, 2);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&i_off_set, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//字符串出力
	if(i_flag_need)
	{
		p_tmp = (char*)frmalloc (i_len);
		if(p_tmp == NULL)
			return FR_FAIL;

		i_ret = bytebuff_get_bytes_at (p_st_data, i_start + i_off_set, i_len, p_tmp);
		if(i_ret == FR_FAIL)
		{
			frfree(p_tmp);
			return FR_FAIL;
		}

		i_ret = iconv_to_utf8 (p_tmp, i_len, "unicode", &p_out, (unsigned int *)&i_out_size);
		if(i_ret == 2)
		{
			frfree(p_tmp);
			return FR_FAIL;
		}

		frfree(p_tmp);

		*pp_out = p_out;
	}

	return FR_SUCC;

}


/*!
 * dcom attribute 获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \p_i_max_len				(int *					最大长度)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_get_attribute(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int *p_i_max_len, int i_flag_need)
{
	short s_type = 0, s_value_len = 0;
	int i_ret = 0;
	char *p_value = NULL;
	int i_max_len = 0;

	if(p_st_data == NULL || p_st_private == NULL || p_i_max_len == NULL)
		return FR_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
		return FR_FAIL;

	i_max_len = *p_i_max_len;

	//type
	i_ret = bytebuff_get_short (p_st_data, 2, (uint16_t *)&s_type, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;
	i_max_len -= 2;

	//value len
	i_ret = bytebuff_get_short (p_st_data, 2, (uint16_t *)&s_value_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;
	i_max_len -= 2;

	p_value = (char*)frmalloc (s_value_len);
	if(p_value == NULL)
		return FR_FAIL;

	i_ret = bytebuff_get_bytes (p_st_data, p_value, (unsigned int)s_value_len);
	if(i_ret == FR_FAIL)
	{
		frfree(p_value);
		return FR_FAIL;
	}

	switch (s_type)
	{
		//todo
		case 0:
			break;

		default:
			return FR_FAIL;
	}

	i_max_len -= s_value_len;
	frfree(p_value);
	*p_i_max_len = i_max_len;

	return FR_SUCC;

}

/*!
 * dcom target info 获取
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_start					(int 					起始位置)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_get_target_info(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_start, int i_flag_need)
{
	int i_max_len = 0, i_off_set = 0;
	int i_ret = 0;
	int i_pos_pre = 0;

	if(p_st_data == NULL || p_st_private == NULL)
		return FR_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
		return FR_FAIL;

	//len
	i_ret = bytebuff_get_int (p_st_data, 2, (uint32_t *)&i_max_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//max len
	i_ret = bytebuff_skip (p_st_data, 2);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	//off set
	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&i_off_set, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return FR_FAIL;

	i_pos_pre = bytebuff_getPosition (p_st_data);

	bytebuff_setPosition (p_st_data, i_start + i_off_set);

	while (i_max_len)
	{
		i_ret = dcom_get_attribute (p_st_data, p_st_private, p_st_body_data, &i_max_len, i_flag_need);
		if(i_ret == FR_FAIL)
			return FR_FAIL;
	}

	i_ret = bytebuff_setPosition (p_st_data, i_pos_pre);
	return i_ret;

}

/*!
 * dcom bind 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_bind_parse(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data,int i_flag_need)
{
	int i_ret = 0;
	char c_tmp;
	int i_ctx_num = 0;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if(p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	//frag
	i_ret = bytebuff_skip(p_st_data, 1);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//data representation
	i_ret = bytebuff_get_char(p_st_data, (uint8_t *)&c_tmp);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if(c_tmp & 0x10)
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip(p_st_data, 3);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int(p_st_data, 4, (uint32_t *)&p_st_private->i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//max xmit frag   max recv frag
	i_ret = bytebuff_skip(p_st_data, 4);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//Assoc Group: 0x00000000
	i_ret = bytebuff_skip(p_st_data, 4);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//ctx item number
	i_ret = bytebuff_get_int (p_st_data, 2, (uint32_t *)&i_ctx_num, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//ctx item
	while (i_ctx_num--)
	{
		i_ret = dcom_ctx_item(p_st_data, p_st_private, p_st_body_data, i_flag_need);
		if(i_ret == FR_FAIL)
			return APM_L7_ANALYZE_FAIL;
	}

	//Auth flags
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//ntlmssp
	i_ret = bytebuff_skip (p_st_data, 16);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//call workstation domain
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//call workstation name
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//ntlm version
	i_ret = bytebuff_skip (p_st_data, 8);

	return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

}


/*!
 * dcom bind ack解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_bind_ack_parse(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	char c_tmp, *p_target_name = NULL;
	int i_ctx_num = 0, i_start_pos = 0;
	short s_tmp = 0;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if(p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if(i_flag_need && p_st_body_data == NULL)
	return APM_L7_ANALYZE_FAIL;

	//packet flags
	i_ret = bytebuff_skip(p_st_data, 1);
	if(i_ret == FR_FAIL)
		return  APM_L7_ANALYZE_FAIL;

	//data representation
	i_ret = bytebuff_get_char(p_st_data, (uint8_t *)&c_tmp);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if(c_tmp & 0x10)
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip(p_st_data, 3);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int(p_st_data, 4, (uint32_t *)&p_st_private->i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//max xmit frag   max recv frag
	i_ret = bytebuff_skip(p_st_data, 4);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//Assoc Group: 0x00000000
	i_ret = bytebuff_skip(p_st_data, 4);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//dcerpc.cn_sec_addr
	i_ret = bytebuff_get_short (p_st_data, 2, (uint16_t *)&s_tmp, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_skip (p_st_data, (size_t)s_tmp);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//num result
	i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *)&i_ctx_num, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	while (i_ctx_num --)
	{
		i_ret = dcom_ctx_item_ack(p_st_data, p_st_private, p_st_body_data, i_flag_need);
		if(i_ret == FR_FAIL)
			return APM_L7_ANALYZE_FAIL;
	}

	//Auth flags
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//start pos
	i_start_pos = bytebuff_getPosition (p_st_data);

	//ntlmssp
	i_ret = bytebuff_skip (p_st_data, 12);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//target name
	i_ret = dcom_get_string (p_st_data, p_st_private, i_start_pos, &p_target_name, i_flag_need);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//ntlmssp.negotiateflags
	i_ret = bytebuff_skip (p_st_data, 4);
	if(i_ret == FR_FAIL)
	{
		frfree(p_target_name);
		return APM_L7_ANALYZE_FAIL;
	}

	//ntlmssp.ntlmserverchallenge   ntlmssp.reserved
	i_ret = bytebuff_skip (p_st_data, 16);
	if(i_ret == FR_FAIL)
	{
		frfree(p_target_name);
		return APM_L7_ANALYZE_FAIL;
	}

	//target info
	i_ret = dcom_get_target_info(p_st_data, p_st_private, p_st_body_data, i_start_pos, i_flag_need);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//version
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	return APM_L7_ANALYZE_SUCC;

}

/*!
 * dcom req 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_request(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	int i_packet_flag = 0;
	char *p_guid = NULL, *p_arg = NULL;
	char c_tmp;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if ( p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if ( i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	//Packet Flags: 0x83
	i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *) &i_packet_flag, BYTE_BIG_ENDIAN);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//Data Representation: 10000000
	i_ret = bytebuff_get_char (p_st_data, (uint8_t *) &c_tmp);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if ( c_tmp & 0x10 )
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip (p_st_data, 3);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&p_st_private->i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//Alloc hint: 302   Context ID: 2   Opnum: 5
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	//Object UUID: 00001c08-1108-0000-043a-73ce094a70aa
	i_ret = dcom_ctx_guid (p_st_data, p_st_private, &p_guid, i_flag_need);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(p_guid)
	{
		//title
		i_ret = frreport_body_l7_add_str (p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_guid);
		if(i_ret == FR_FAIL)
		{
			frfree(p_guid);
			return APM_L7_ANALYZE_FAIL;
		}

		//title
		i_ret = frreport_body_l7_add_str (p_st_body_data, "request.rpc.fuction", p_guid);
		if(i_ret == FR_FAIL)
		{
			frfree(p_guid);
			return APM_L7_ANALYZE_FAIL;
		}
		frfree(p_guid);
	}

	if(i_flag_need)
	{
		if(p_st_data->ui_remaining == 0)
			return APM_L7_ANALYZE_SUCC;

		i_ret = frreport_body_l7_add_int (p_st_body_data, "request.rpc.arg.size", 1);
		if(i_ret == FR_FAIL)
			return APM_L7_ANALYZE_FAIL;


		p_arg = (char*)frmalloc (p_st_data->ui_remaining);
		if(p_arg == NULL)
			return APM_L7_ANALYZE_FAIL;

		i_ret = bytebuff_peek_bytes (p_st_data, p_arg, p_st_data->ui_remaining);
		if(i_ret == FR_FAIL)
		{
			frfree(p_arg);
			return APM_L7_ANALYZE_FAIL;
		}

		i_ret = frreport_body_l7_add_bin (p_st_body_data, "request.rpc.arg.1", p_arg, p_st_data->ui_remaining);
		if(i_ret == FR_FAIL)
		{
			frfree(p_arg);
			return APM_L7_ANALYZE_FAIL;
		}

		frfree(p_arg);

	}

	return APM_L7_ANALYZE_SUCC;

}

/*!
 * dcom resp 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_response(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	int i_packet_flag = 0;
	char *p_arg = NULL;
	int i_call_id = 0;
	char c_tmp;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if ( p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if ( i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	//Packet Flags: 0x83
	i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *) &i_packet_flag, BYTE_BIG_ENDIAN);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//Data Representation: 10000000
	i_ret = bytebuff_get_char (p_st_data, (uint8_t *) &c_tmp);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if ( c_tmp & 0x10 )
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip (p_st_data, 3);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL || i_call_id != p_st_private->i_call_id)
		return APM_L7_ANALYZE_FAIL;


	//Alloc hint: 16   Context ID: 2   Cancel count: 0
	i_ret = bytebuff_skip (p_st_data, 8);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(i_flag_need)
	{
		if(p_st_data->ui_remaining == 0)
			return APM_L7_ANALYZE_SUCC;

		p_arg = (char*)frmalloc (p_st_data->ui_remaining);
		if(p_arg == NULL)
			return APM_L7_ANALYZE_FAIL;

		i_ret = bytebuff_peek_bytes (p_st_data, p_arg, p_st_data->ui_remaining);
		if(i_ret == FR_FAIL)
		{
			frfree(p_arg);
			return APM_L7_ANALYZE_FAIL;
		}

		i_ret = frreport_body_l7_add_bin (p_st_body_data, "response.rpc.return", p_arg, p_st_data->ui_remaining);
		if(i_ret == FR_FAIL)
		{
			frfree(p_arg);
			return APM_L7_ANALYZE_FAIL;
		}

		frfree(p_arg);

	}

	return APM_L7_ANALYZE_SUCC;

}


/*!
 * dcom 其他类型 req 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_other_type_req(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	int i_packet_flag = 0;
	char c_tmp;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if ( p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if ( i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	//Packet Flags: 0x83
	i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *) &i_packet_flag, BYTE_BIG_ENDIAN);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//Data Representation: 10000000
	i_ret = bytebuff_get_char (p_st_data, (uint8_t *) &c_tmp);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if ( c_tmp & 0x10 )
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip (p_st_data, 3);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&p_st_private->i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	return APM_L7_ANALYZE_SUCC;

}

/*!
 * dcom 其他类型 resp 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_other_type_resp(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	int i_packet_flag = 0;
	int i_call_id = 0;
	char c_tmp;
	uint16_t u16_frag_len = 0, u16_auth_len = 0;

	if ( p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if ( i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	//Packet Flags: 0x83
	i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *) &i_packet_flag, BYTE_BIG_ENDIAN);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//Data Representation: 10000000
	i_ret = bytebuff_get_char (p_st_data, (uint8_t *) &c_tmp);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//little endian
	if ( c_tmp & 0x10 )
		p_st_private->i_packet_endian = BYTE_LITTLE_ENDIAN;
	else
		p_st_private->i_packet_endian = BYTE_BIG_ENDIAN;

	//charset
	p_st_private->i_charset = c_tmp & 0x0f;

	//float point
	i_ret = bytebuff_skip (p_st_data, 3);
	if ( i_ret == FR_FAIL )
		return APM_L7_ANALYZE_FAIL;

	//frag len auth len
	i_ret = bytebuff_get_short(p_st_data, 2, &u16_frag_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	i_ret = bytebuff_get_short(p_st_data, 2, &u16_auth_len, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL)
		return APM_L7_ANALYZE_FAIL;

	if(u16_frag_len != p_st_data->ui_all_len)
		return APM_L7_ANALYZE_FAIL;

	//call id
	i_ret = bytebuff_get_int (p_st_data, 4, (uint32_t *)&i_call_id, (LITTLE_BIG_ENDIAN)p_st_private->i_packet_endian);
	if(i_ret == FR_FAIL || i_call_id != p_st_private->i_call_id)
		return APM_L7_ANALYZE_FAIL;

	return APM_L7_ANALYZE_SUCC;

}

/*!
 * dcom 数据包 解析
 *
 * \p_st_data				(Frbyte_Packet *		输入数据)
 * \p_st_private			(L7session_dcom_private *		私有数据)
 * \p_st_body_data			(Frreport_body_data *	上报链表)
 * \i_flag_need				(int					是否需要数据）
 *
 * \return			FR_FAIL:失败\n
 * 					FR_SUCC:成功\n
 */
int dcom_parse(Frbyte_Packet *p_st_data, L7session_dcom_private *p_st_private, Frreport_body_data *p_st_body_data, int i_flag_need)
{
	int i_ret = 0;
	uint8_t u8_version = 0;

	if ( p_st_data == NULL || p_st_private == NULL)
		return APM_L7_ANALYZE_FAIL;

	if ( i_flag_need && p_st_body_data == NULL)
		return APM_L7_ANALYZE_FAIL;

	if(p_st_private->i_packet_type == 0x0100)
	{
		//版本判断
		i_ret = bytebuff_get_char(p_st_data, &u8_version);
		if(i_ret == FR_FAIL || u8_version > 9)
			return APM_L7_ANALYZE_FAIL;

		i_ret = bytebuff_get_char(p_st_data, &u8_version);
		if(i_ret == FR_FAIL || u8_version > 9)
			return APM_L7_ANALYZE_FAIL;

		i_ret = bytebuff_get_int (p_st_data, 1, (uint32_t *)&p_st_private->i_packet_type, BYTE_BIG_ENDIAN);
		if(i_ret == FR_FAIL)
			return APM_L7_ANALYZE_FAIL;
	}

	switch (p_st_private->i_packet_type)
	{
		case 0x00:
			i_ret = dcom_request (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			p_st_private->i_flag_report = 1;
			break;

		case 0x02:
			i_ret = dcom_response (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			p_st_private->i_flag_report = 1;
			break;

		case 0x0b:
			i_ret = dcom_bind_parse (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			p_st_private->i_flag_report = 0;
			break;

		case 0x0c:
			i_ret = dcom_bind_ack_parse (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			p_st_private->i_flag_report = 0;
			break;

		default:
			if(p_st_private->i_use_request)
				i_ret = dcom_other_type_req (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			else
				i_ret = dcom_other_type_resp (p_st_data, p_st_private, p_st_body_data, i_flag_need);
			p_st_private->i_flag_report = 0;
			break;

	}

	return i_ret;
}
